######################################################################
#
# SOAP Web Services Wrapper
######################################################################
package EP::WS::SOAP;
#use strict;

use SOAP::Lite +trace;

use EP::Config;
use EP::Common;

use EP::Common::DBI;
use EP::Common::DBI::Session;
use EP::Common::DBI::Action;
use EP::Common::DBI::Action_Metadata;
use EP::Common::DBI::Dataset;

use EP::EPC::Core;

use CGI;
# this would go somewhere... not sure where

sub check_expired_sessions {
    # check if there are sessions to cleanup... useful as SOAP callers will never clean up after themself...
}

sub get_session_if_not_expired {
    my ($session_id) = @_;

    my $session = retrieve EP::Common::DBI::Session( $session_id );

    die "Invalid session id ($session_id)"
        if not $session;

    if ($session and $session->expired) {
        $session->delete();
        die "Your session had expired and was terminated -- please start a new session";
    }
 
    return $session;
}

sub get_value_by_tag {
    my ($string, $tag) = @_;

    if (not ($string =~ m/$tag\s*=\s*\"([^\"]+)\"/)) {
        die "No tag ($tag) found in sting ($string)";
    }

    return $1;
}

sub do_process_component {
    my ( $session, $component_id, $parameters ) = @_;

    my %request_form_data;

    $request_form_data{"session_id"} = $session->id;
    $request_form_data{"local_mode"} = "1";
    $request_form_data{"process_component_id"} = $component_id;
    foreach my $parameter (keys %{$parameters}) {
        $request_form_data{$parameter} = $$parameters{$parameter};
    }

    $request_form_data{request_user_agent} = "SOAP Caller/0.10";

    $request_form_data{current_folder_id} = $session->current_folder->id if $session->current_folder;
    $request_form_data{current_root_dataset_id} = $session->current_root_dataset->id if $session->current_root_dataset;
    $request_form_data{current_action_id} = $session->current_action->id if $session->current_action;
    $request_form_data{current_cluster_selection} = $session->current_cluster_selection if $session->current_cluster_selection;
    $request_form_data{current_metadata_selection} = $session->current_metadata_selection if $session->current_metadata_selection;

    my $fake_cgi_query = new CGI( \%request_form_data );
    my $core_dd = new EP::EPC::Core::Dispatcher( $fake_cgi_query );

    $core_dd->dispatch_request() if not $core_dd->{error};  # so what do we do if there is an error???

    my $res = $core_dd->result_content();

    if ($res =~ m/<error.*>(.+)<\/error>/) {
        die $1;
    }

    if ($res =~ m/<epc_output\s*(.*)\s*\/>/) {
        $res = $1;
    } else {
        die "Bad response ($res) received";
    }

    return $res;
}

######################################################################

sub epLogin {
    my ($this, $username, $password) = @_;

    my $session = EP::Common::DBI::Session->create ({});
    warn "[SOAP:epLogin] Got session $session";

    if ("" eq $username) {
        $username = "guest";
        $password = "guest";
    }

    my $response = do_process_component($session, 0, {username => $username, password => $password});

    return ($session->id);
}

sub epGuestLogin {
    my ($this) = @_;

    my $session = EP::Common::DBI::Session->create ({});
    warn "[SOAP:epLogin] Got session $session";

    my $response = do_process_component($session, 0, {username => "guest", password => "guest"});

    return ($session->id);
}

sub epUploadTableFromURL {
    my ($this, $session_id, $url, $format, $custom_delimiter, $first_data_column, $first_data_row, $species) = @_;

    my $session = get_session_if_not_expired($session_id);

    my $response = do_process_component($session, 100,
        { active_subsection_id => [0]
        , src_url => [$url]
        , filetype => [$format]
        , cust_delim => [$custom_delimiter]
        , m => [$first_data_column]
        , n => [$first_data_row]
        , dataset_name => ['']
        , dataset_species => [$species]
        , upload_data_type => 'exp::user' });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epUploadAffyFromURL {
    my ($this, $session_id, $url) = @_;

    my $session = get_session_if_not_expired($session_id);

    my $response = do_process_component($session, 100,
        { active_subsection_id => [1]
        , src_url => [$url]
        , upload_data_type => 'exp::affy' });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epUploadFromArrayExpress {
    my ($this, $session_id, $ae_accession_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    my $response = do_process_component($session, 100,
        { arrayexpress_data_export => [$ae_accession_id]
        , dataset_name => [$ae_accession_id],
        , upload_data_type => 'exp::arrayexpress' });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataSelectionByValueRanges {
    my ($this, $session_id, $n_stdevs, $percent_columns, $n_greatest_stdevs) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 2,
        { active_subsection_id => 0
        , greatest_n_stdevs => [$n_greatest_stdevs]
        , subselect_stdev => [$n_stdevs]
        , subselect_stdev_columns => [$percent_columns] });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataSelectionByMissingValues {
    my ($this, $session_id, $max_percentage_of_missing_values) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 2,
        { active_subsection_id => 1
        , subselect_na_values => [$max_percentage_of_missing_values] });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataSelectionByColumnIds {
    my ($this, $session_id, $column_ids_to_select) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 2,
        { active_subsection_id => 2
        , subselect_column_headers => [$column_ids_to_select] });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataSelectionByRowIds {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataSelectionByGeneSimilarity {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataSelectionLimma {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epMissingValuesImputationWithZeroes {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epMissingValuesImputationWithRowAverages {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epMissingValuesImputationByKNN {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataTransformationIntensityToLogNRatio {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataTransformationRatioToLogNRatio {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataTransformationAverageRowIdentifiers {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataTransformationTranspose {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataTransformationAbsoluteToRelative {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataTransformationMeanCenter {
    my ($this, $session_id) = @_;

    my $session = get_session_if_not_expired($session_id);

    return ($session->id, 0);
}

sub epDataNormalizationGCRMA {
    my ($this, $session_id) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 112,
        { active_subsection_id => 0
        , normalization_gcrma => [1]
        });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataNormalizationRMA {
    my ($this, $session_id) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 112,
        { active_subsection_id => 1
        , normalization_rma => [1]
        });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataNormalizationLiAndWong {
    my ($this, $session_id) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 112,
        { active_subsection_id => 2
        , normalization_liwong => [1]
        });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epDataNormalizationVSN {
    my ($this, $session_id) = @_;
    
    my $session = get_session_if_not_expired($session_id);
    my $response = do_process_component($session, 112,
        { active_subsection_id => 3
        , normalization_vsn => [1]
        });

    return ($session->id, get_value_by_tag($response, "action_id"));
}

sub epGetActionMetadata {
    my ($this, $session_id, $action_id, $tag ) = @_;
    
    my $session = get_session_if_not_expired($session_id);

    my ($metadata) = EP::Common::DBI::Action_Metadata->search({ action => $action_id, name => $tag });
    die "Unable to obtain metadata for action ($action_id) with name ($tag)"
        if (not defined $metadata);

    return ($session->id, $metadata->value);
}

sub epGetColumnIds {
    my ($this, $session_id, $action_id ) = @_;

    my $session = get_session_if_not_expired($session_id);

    my ($action) = EP::Common::DBI::Action->retrieve( $action_id );
    die "Unable to obtain action data for action ($action_id)"
        if (not defined $action);

    my $cols = $EP::Config::h->{EPNG_USRDATA_PATH} . "/" . $action->dst_dataset->folder->location . "/" . $action->dst_dataset->filename . ".columns";
    my @results;

    open COLUMNS, "< $cols" || die "Unable to open $cols";
    if (<COLUMNS>) {
        <COLUMNS>;
    }
    
    while (<COLUMNS>) {
        chomp;
        my @column = split /\t/, $_;#, 2;
        push @results, $column[1];
    }
    close COLUMNS;

    return ($session_id, \@results);
}

sub epGetRowIds {
    my ($this, $session_id, $action_id ) = @_;

    my $session = get_session_if_not_expired($session_id);

    my ($action) = EP::Common::DBI::Action->retrieve( $action_id );
    die "Unable to obtain action data for action ($action_id)"
        if (not defined $action);

    my $rows = $EP::Config::h->{EPNG_USRDATA_PATH} . "/" . $action->dst_dataset->folder->location . "/" . $action->dst_dataset->filename . ".rows";
    my @results;

    open ROWS, "< $rows" || die "Unable to open $rows";
    if (<ROWS>) {
        <ROWS>;
    }
    
    while (<ROWS>) {
        chomp;
        my @row = split /\t/, $_;#, 2;
        push @results, $row[1];
    }
    close ROWS;

    return ($session_id, \@results);
}

sub dispatch {
    my ($a1, $a2, $a3, $a4, $a5) = @_;

    return ["[xxxx]", "yyyy"];
}

our $method_called = '';

1;
